package com.jrzh.mvc.service.sys.impl;

import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jrzh.common.exception.ProjectException;
import com.jrzh.common.tools.CollectionTools;
import com.jrzh.common.tools.JsonTools;
import com.jrzh.common.utils.ReflectUtils;
import com.jrzh.framework.base.convert.BaseConvertI;
import com.jrzh.framework.base.repository.BaseRepository;
import com.jrzh.framework.base.search.BaseSearch;
import com.jrzh.framework.base.service.impl.BaseServiceImpl;
import com.jrzh.framework.bean.JqGridTree;
import com.jrzh.framework.bean.SessionUser;
import com.jrzh.framework.bean.TreeViewBean;
import com.jrzh.mvc.constants.SysActionConstants;
import com.jrzh.mvc.constants.SysConstant.RESOURCE_TYPE;
import com.jrzh.mvc.convert.sys.ResourcesConvert;
import com.jrzh.mvc.model.sys.ResourcesModel;
import com.jrzh.mvc.model.sys.RoleModel;
import com.jrzh.mvc.repository.sys.ResourcesRepository;
import com.jrzh.mvc.search.sys.ResourcesSearch;
import com.jrzh.mvc.service.sys.ResourcesServiceI;
import com.jrzh.mvc.view.sys.ResourcesView;

@Service("resourcesService")
public class ResourcesServiceImpl extends
		BaseServiceImpl<ResourcesModel, ResourcesSearch, ResourcesView>
		implements ResourcesServiceI {

	@Autowired
	private ResourcesRepository resourcesRepository;
	
	@Autowired
	private ResourcesConvert resourcesConvert;
	
	public BaseConvertI<ResourcesModel, ResourcesView> getConvert() {
		return resourcesConvert;
	}

	@Override
	public BaseRepository<ResourcesModel, Serializable> getDao() {
		return resourcesRepository;
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
	public void deleteAndChildren(ResourcesModel model, SessionUser user)
			throws ProjectException {
		List<ResourcesModel> list = this.findAll();
		Set<ResourcesModel> deleteModels = getChildrenByParentId(list, model);
		deleteModels.add(model);
		this.deletes(deleteModels, user);
	}

	private Set<ResourcesModel> getChildrenByParentId(
			List<ResourcesModel> list, ResourcesModel model)
			throws ProjectException {
		Set<ResourcesModel> models = new HashSet<ResourcesModel>();
		if (CollectionTools.isNotBlank(list)) {
			for (ResourcesModel m : list) {
				if (StringUtils.equals(m.getPid(), model.getId())) {
					models.add(model);
					if (hasChildren(list, model)) {
						models.addAll(getChildrenByParentId(list, m));
					}
				}
			}
		}
		return models;
	}

	private Boolean hasChildren(List<ResourcesModel> list, ResourcesModel model)
			throws ProjectException {
		Boolean result = false;
		if (CollectionTools.isNotBlank(list)) {
			for (ResourcesModel m : list) {
				if (StringUtils.equals(m.getPid(), model.getId())) {
					result = true;
					break;
				}
			}
		}
		return result;
	}

	@Override
	public List<TreeViewBean> getTreeByRole(ResourcesSearch search,RoleModel role)throws ProjectException {
		List<TreeViewBean> treeList = new ArrayList<TreeViewBean>();
		Map<String, TreeViewBean> treeMap = new HashMap<String, TreeViewBean>();
		 List<ResourcesModel> models = this.list(search);
		 //转换资源
		 for(ResourcesModel model : models){
			  TreeViewBean tree = new ResourcesConvert().convertToTreeView(model);
			  treeMap.put(model.getId(), tree);
		 }
		//遍历角色的资源权限，设置默认选中
		 List<ResourcesModel> resourcesList = role.getResources();
			for(ResourcesModel resource : resourcesList){
				log.info(resource.getId());
				TreeViewBean roleTree = treeMap.get(resource.getId());
				Map<String, Boolean> state = new HashMap<String, Boolean>();
				if(roleTree != null){
					state = roleTree.getState();
					state.put("checked", true);
				}
			}
		//生成树
		 for(ResourcesModel model : models){
			 if(StringUtils.isBlank(model.getPid())){
				 String prentId = model.getId();
				 TreeViewBean tree = treeMap.get(prentId);
				 List<TreeViewBean> nodes = treeMenuList(treeMap,prentId);
				//排序
				 Collections.sort(nodes);
				 tree.setNodes(nodes);
				 treeList.add(tree);
			 }
		 }
		return treeList;
	}
	
	//获取树的分支
   public List<TreeViewBean> treeMenuList(Map<String, TreeViewBean> treeMap,String parentId) {  
	   List<TreeViewBean> treeList = new ArrayList<TreeViewBean>();
       for (Entry<String, TreeViewBean> entry : treeMap.entrySet()) {
    	   TreeViewBean tree = entry.getValue();
    	   String id = tree.getTags()[0];
    	   String pId = tree.getTags()[1];
           if (StringUtils.equals(pId, parentId)) {  
        	   List<TreeViewBean> nodes = treeMenuList(treeMap,id);  
        	   if(nodes.size()>0){
        		   tree.setNodes(nodes);
        	   }
        	   treeList.add(tree);
           }
       }
       return treeList;  
   }  
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	@Override
	public void saveInit(String project, InputStream in)
			throws ProjectException {
		if (null != in) {
			log.info("###########同步" + project + "模块 ~~~~~~~~~资源表数据 Begin");
			JSONArray array = JsonTools.getFromFile(in);
			List<String> inCodes = new ArrayList<String>();
			if (null != array && array.size() > 0) {
				for (int i = 0; i < array.size(); i++) {
					ResourcesModel resourcesModel = new ResourcesModel();
					JSONObject jsonObject = array.getJSONObject(i);
					String module = jsonObject.getString("module");
					if (StringUtils.isBlank(module)) continue;
					String path = jsonObject.getString("path");
					String model = jsonObject.getString("model");
					String method = jsonObject.getString("method");
					String icon = jsonObject.getString("icon");
					Integer level = jsonObject.getInteger("level");
					Boolean isLeaf = jsonObject.getBoolean("isLeaf");
					Boolean expanded = jsonObject.getBoolean("expanded");
					Boolean isDisable = jsonObject.getBoolean("isDisable");
					Boolean isCustom = jsonObject.getBoolean("isCustom");
					String name = jsonObject.getString("name");
					String btnStr = jsonObject.getString("btns");
					String code = module
							+ (StringUtils.isNotBlank(path) ? "_" + path : "")
							+ (StringUtils.isNotBlank(model) ? "_" + model : "")
							+ (StringUtils.isNotBlank(method) ? "_" + method : "");
					inCodes.add(code);
					Integer type = jsonObject.getInteger("type");
					if (RESOURCE_TYPE.FUNC.equals(type)) {
						String url = module
								+ "/admin/"
								+ (StringUtils.isNotBlank(path) ? path.replace("_", "/") + "/" : "") + model + "/"
								+ method + ".html";
						resourcesModel.setUrl(url);
					}
					resourcesModel.setIcon(icon);
					resourcesModel.setCode(code);
					resourcesModel.setName(name);
					resourcesModel.setType(type);
					resourcesModel.setIsDisable(isDisable);
					resourcesModel.setIsLeaf(isLeaf);
					resourcesModel.setExpanded(expanded);
					resourcesModel.setLevel(level);
					if(null != isCustom){
						resourcesModel.setIsCustom(isCustom);
					}
					String pCode = "";
					// 通过编号得到父节点
					if (StringUtils.isNotBlank(path)) {
						if (StringUtils.contains(path, "_")) {
							String[] _a = path.split("_");
							pCode = module + "_"
									+ path.replace("_" + _a[_a.length - 1], "");
						} else {
							if (StringUtils.isNotBlank(model)) {
								pCode = module + "_" + path;
							} else {
								pCode = module;
							}
						}
					} else {
						if (StringUtils.isNotBlank(model)) {
							pCode = module;
						}
					}
					ResourcesModel pModel = this.findByField("code", pCode);
					String pid = null == pModel || StringUtils.isBlank(pCode) ? ""
							: pModel.getId();
					ResourcesModel _m = resourcesModel;
					_m.setPid(pid);
					_m.setParentId(pid);
					_m.setSortNum(i + 1);
					ResourcesModel dbm = this.findByField("code", code);
					if (null == dbm) {
						log.info("######新增" + _m.getCode());
						_m.setExpanded(true);
						this.add(_m, SessionUser.getSystemUser());
						saveBtns(btnStr, _m, inCodes);
					} else {
						if (!equals(dbm, _m)) {
							log.info("######编辑" + _m.getCode());
							ReflectUtils.copySameFieldToTargetFilterNull(_m, dbm);
							dbm.setExpanded(true);
							this.edit(dbm, SessionUser.getSystemUser());
						}
						saveBtns(btnStr, dbm, inCodes);
					}
				}

			/*	// 处理删除的数据
				ResourcesSearch search = new ResourcesSearch();
				search.setNotInCodes(inCodes.toArray(new String[] {}));
				search.setLikeHeadCode(project);
				List<ResourcesModel> list = this.list(search);*/
				/*if (CollectionTools.isNotBlank(list)) {
					for (ResourcesModel r : list) {
						log.info("######删除" + r.getCode());
						this.delete(r.getId(), SessionUser.getSystemUser());
					}
				}*/
			}
			log.info("###########同步" + project + "模块 资源表数据 End");
		}
	}
	
	private void saveBtns(String btnStr, ResourcesModel func, List<String> inCodes) {
		if(StringUtils.isBlank(btnStr)) return;
		SessionUser sessionUser = SessionUser.getSystemUser();
		Date now = new Date();
		String [] btns = StringUtils.split(btnStr, ",");
		if(null == btns || btns.length == 0) return;
		List<ResourcesModel> actionList = selectByField("parentId", func.getId());
		for(int i = 0 ; i <  btns.length; i ++) {
			String btn = btns[i];
			if(StringUtils.isBlank(btn)) continue;
			String code = func.getCode() +"_" + btn;
			inCodes.add(code);
			ResourcesModel action = CollectionTools.searchObject(actionList, "code", code);
			if(null == action) {
				action = new ResourcesModel();
				action.setCreateBy(sessionUser.format());
				action.setCreateTime(now);
			}
			action.setCode(code);
			action.setIcon("glyphicon-menu-hamburger");
			action.setParentId(func.getId());
			action.setPid(func.getId());
			action.setName(SysActionConstants.valueMap.get(btn));
			action.setType(RESOURCE_TYPE.ACTION);
			action.setIsDisable(false);
			action.setIsLeaf(true);
			action.setExpanded(true);
			action.setLevel(3);
			action.setUpdateBy(sessionUser.format());
			action.setUpdateTime(now);
			action.setSortNum(i+1);
			resourcesRepository.save(action);
		}
	}
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	@Override
	public void saveInitList(String project, List<InputStream> ins)
			throws ProjectException {
		if (null != ins) {
			log.info("###########同步" + project + "模块 ~~~~~~~~~资源表数据 Begin");
			List<String> inCodes = new ArrayList<String>();
			for(InputStream in : ins){
				JSONArray array = JsonTools.getFromFile(in);
				
				if (null != array && array.size() > 0) {
					for (int i = 0; i < array.size(); i++) {
						ResourcesModel resourcesModel = new ResourcesModel();
						JSONObject jsonObject = array.getJSONObject(i);
						String module = jsonObject.getString("module");
						if (StringUtils.isBlank(module))
							continue;
						String path = jsonObject.getString("path");
						String model = jsonObject.getString("model");
						String method = jsonObject.getString("method");
						String icon = jsonObject.getString("icon");
						Integer level = jsonObject.getInteger("level");
						Boolean isLeaf = jsonObject.getBoolean("isLeaf");
						Boolean expanded = jsonObject.getBoolean("expanded");
						Boolean isDisable = jsonObject.getBoolean("isDisable");
						Boolean isCustom = jsonObject.getBoolean("isCustom");
						String name = jsonObject.getString("name");
						String code = module
								+ (StringUtils.isNotBlank(path) ? "_" + path : "")
								+ (StringUtils.isNotBlank(model) ? "_" + model : "")
								+ (StringUtils.isNotBlank(method) ? "_" + method
										: "");
						inCodes.add(code);
						Integer type = jsonObject.getInteger("type");
						if (RESOURCE_TYPE.FUNC.equals(type)) {
							String url = module
									+ "/admin/"
									+ (StringUtils.isNotBlank(path) ? path.replace(
											"_", "/") + "/" : "") + model + "/"
									+ method + ".html";
							resourcesModel.setUrl(url);
						}
						resourcesModel.setIcon(icon);
						resourcesModel.setCode(code);
						resourcesModel.setName(name);
						resourcesModel.setType(type);
						resourcesModel.setIsDisable(isDisable);
						resourcesModel.setIsLeaf(isLeaf);
						resourcesModel.setExpanded(expanded);
						resourcesModel.setLevel(level);
						if(null != isCustom){
							resourcesModel.setIsCustom(isCustom);
						}
						String pCode = "";
						// 通过编号得到父节点
						if (StringUtils.isNotBlank(path)) {
							if (StringUtils.contains(path, "_")) {
								String[] _a = path.split("_");
								pCode = module + "_"
										+ path.replace("_" + _a[_a.length - 1], "");
							} else {
								if (StringUtils.isNotBlank(model)) {
									pCode = module + "_" + path;
								} else {
									pCode = module;
								}
							}
						} else {
							if (StringUtils.isNotBlank(model)) {
								pCode = module;
							}
						}
						ResourcesModel pModel = this.findByField("code", pCode);
						String pid = null == pModel || StringUtils.isBlank(pCode) ? ""
								: pModel.getId();
						ResourcesModel _m = resourcesModel;
						_m.setPid(pid);
						_m.setParentId(pid);
						_m.setSortNum(i + 1);
						ResourcesModel dbm = this.findByField("code", code);
						if (null == dbm) {
							log.info("######新增" + _m.getCode());
							this.add(_m, SessionUser.getSystemUser());
						} else {
							if (!equals(dbm, _m)) {
								log.info("######编辑" + _m.getCode());
								ReflectUtils.copySameFieldToTargetFilterNull(_m,
										dbm);
								this.edit(dbm, SessionUser.getSystemUser());
							}
						}
					}
					
				}
			}
			
			// 处理删除的数据
			ResourcesSearch search = new ResourcesSearch();
			search.setNotInCodes(inCodes.toArray(new String[] {}));
			search.setLikeHeadCode(project);
			List<ResourcesModel> list = this.list(search);
			if (CollectionTools.isNotBlank(list)) {
				for (ResourcesModel r : list) {
					log.info("######删除" + r.getCode());
					this.delete(r.getId(), SessionUser.getSystemUser());
				}
			}
			log.info("###########同步" + project + "模块 资源表数据 End");
		}
	}

	private Boolean equals(ResourcesModel source, ResourcesModel target) {
		return StringUtils.equals(source.getCode(), target.getCode())
				&& StringUtils.equals(source.getPid(), target.getPid())
				&& StringUtils.equals(source.getName(), target.getName())
				&& StringUtils.equals(source.getIcon(), target.getIcon())
				&& StringUtils.equals(source.getRemark(), target.getRemark())
				&& StringUtils.equals(source.getUrl(), target.getUrl())
				&& source.getType() == target.getType()
				&& source.getSortNum() == target.getSortNum()
				&& source.getIsDisable() == target.getIsDisable() 
				&& source.getIsLeaf() == target.getIsLeaf();
	}

	@Override
	public JqGridTree treegrid(ResourcesSearch search, SessionUser sessionUser) throws ProjectException { 
		JqGridTree tree = new JqGridTree();
		search.setOrder(BaseSearch.Order_Type_Asc);
		search.setSort("sortNum");
    	List<ResourcesModel> list = list(search);
    	if(CollectionTools.isNotBlank(list)){
    		List<ResourcesView> result = new ArrayList<ResourcesView>();
    		List<ResourcesView> viewList = resourcesConvert.convertToViewListI18n(list, sessionUser);
    		List<ResourcesView> rootList = CollectionTools.searchObjects(viewList, "level", 1);
    		for(ResourcesView root : rootList) {
    			result.add(root);
    			result.addAll(findChildren(viewList, root));
    		}
			tree.setRecords(result.size());
			tree.setTotal(result.size());
			tree.setRows(result);
    	}
		return tree;
	}
	
	private List<ResourcesView> findChildren(List<ResourcesView> viewList, ResourcesView parent) {
		List<ResourcesView> resultList = new ArrayList<ResourcesView>();
		List<ResourcesView> childList = CollectionTools.searchObjects(viewList, "pid", parent.getId());
		if(CollectionTools.isNotBlank(childList)) {
			for(ResourcesView child : childList) {
				resultList.add(child);
				resultList.addAll(findChildren(viewList, child));
			}
		}
		return resultList;
	}

}
